<?php
/**
 * RAI服务对象解释器
 *
 * @version $Id: RaiInterpreter.php 312 2008-04-23 16:29:38Z iwind $
 * @package net.4kiki.rai.server
 * @since 0.0.3
 */
class RaiInterpreter {
	private $serivceMap = array();
	
	/**
	 * 激活
	 *
	 */
	public function invoke() {
		$input = $this->getInput();
		$format = RaiConfig::detectFormat($input);
		$request = $format->decodeRequest($input);
		$serviceName = $request->getServiceName();
		$response = new RaiResponse();

		try {
			if (!isset($this->serivceMap[$serviceName])) {
				$response->setFault(new RaiFault(0, "can't find service '{$serviceName}'"));
			}
			else {
				$methodName = $request->getMethodName();
				if ($methodName === null) {
					$response->setFault(new RaiFault(0, "unkonwn request method name"));
				}
				else {
					$service = $this->serivceMap[$serviceName];
					
					//validate
					$validators = $service->getValidators();
					$permission = true;
					foreach ($validators as $validator) {
						$validator->setRequest($request);
						if (!$validator->validate()) {
							$response->setFault($validator->getFault());
							$permission = false;
							break;
						}
					}
					
					if ($permission) {
						$realObject = $service->getObject();
						if (!method_exists($realObject, $methodName)) {
							$response->setFault(new RaiFault(0, "can't find method by name '{$methodName}' in service '{$serviceName}'"));
						}
						else if (!is_callable(array($realObject, $methodName))) {
							$response->setFault(new RaiFault(0, "method '{$methodName}' is not callable"));
						}
						else {
							$reflectionClass = new IReflection(get_class($realObject));
							$data = $reflectionClass->invoke($realObject, $methodName, $request->getArguments());
							if (is_object($data) && ($data instanceof RaiResponse)) {
								$response = $data;	
							}
							else {
								$response->setData($data);
							}
						}
					}
				}
			}
		} catch (IReflectionTooFewArgumentsException $e) {
			$response->setFault(new RaiFault($e->getCode(), "method '" . $request->getMethodName() . "' in service '" . $request->getServiceName() . "' need more arguments"));
		} catch (Exception  $e) {
			$response->setFault(new RaiFault($e->getCode(), $e->getMessage()));
		}
		echo $format->encodeResponse($response);
	}
	
	/**
	 * 注册服务
	 *
	 * @param string $serviceName 服务名
	 * @param RaiService $service 服务对象
	 */
	public function register($serviceName, RaiService $service) {
		$this->serivceMap[$serviceName] = $service;
	}
	
	/**
	 * 取得Http输入的数据
	 *
	 * @return string
	 */
	private function getInput() {
		$stream = fopen("php://input", "r");
		$input = "";
		if ($stream) {
			while (!feof($stream)) {
				$input .= fgets($stream);
			}
			fclose($stream);
		}
		return $input;
	}
}

?>